using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using PEMath;
using PEPhysx;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.SceneManagement;

/****************************************************
// 功能：资源加载管理器
// | Talk To [ 聊来改善地区金融服务环境，助力企业发展 ]
// | Copyright (c) 2021-2025 聊来 All rights reserved.
// | Licensed ( <a href="http://www.apache.org/licenses/LICENSE-2.0">聊来</a> )
// | @Author: 贯彻己道的云 <18970881148@qq.com>
// | DateTime: 2025/1/3 10:38:33
*****************************************************/

public class ResourceManager : SingletonPatternMonoBase<ResourceManager>, IManager
{
    private Action progressAction;
    private readonly Dictionary<string, Sprite> spriteDic = new Dictionary<string, Sprite>();
    private readonly Dictionary<string, GameObject> gameDic = new Dictionary<string, GameObject>();
    private readonly Dictionary<string,AudioClip> audioDic = new Dictionary<string,AudioClip>();
    private readonly Dictionary<int, UnitConfig> unitDataDic = new Dictionary<int, UnitConfig>();
    private readonly Dictionary<int, MapConfig> mapDataDic = new Dictionary<int, MapConfig>();
    protected internal LoadingWindow loadingWindow;

    public void InitManager()
    {
        //Debug.Log("ResourceManager Init");
        InitUnitConfig(Constants.UNIT_CONFIG);
        InitMapConfig(Constants.MAP_CONFIG);
    }

    /// <summary>
    /// 异步加载场景
    /// </summary>
    /// <param name="name"></param>
    /// <param name="loaded"></param>
    public void AsyncLoadScene(string name, Action loaded)
    {
        // 显示加载进度页面
        UIManager.Instance.Open(WindowName.Loading, null);

        var sceneAsync = SceneManager.LoadSceneAsync(name);
        progressAction = () =>
        {
            var progress = sceneAsync.progress;
            loadingWindow.SetProgress(progress);
            if (!(Math.Abs(progress - 1) <= 0)) return;

            loaded?.Invoke();
            progressAction = null;
            sceneAsync = null;
        };
    }

    /// <summary>
    /// 异步加载场景
    /// </summary>
    /// <param name="name"></param>
    /// <param name="loadRate"></param>
    /// <param name="loaded"></param>
    public void AsyncScene(string name, Action<float> loadRate, Action loaded)
    {
        var sceneAsync = SceneManager.LoadSceneAsync(name);
        progressAction = () =>
        {
            var progress = sceneAsync.progress;
            loadRate?.Invoke(progress);
            if (!(Math.Abs(progress - 1) <= 0)) return;
            
            loaded?.Invoke();
            progressAction = null;
            sceneAsync = null;
        };
    }

    private void Update()
    {
        progressAction?.Invoke();
    }
    
    /// <summary>
    /// 加载Sprite资源文件
    /// </summary>
    /// <param name="path"></param>
    /// <param name="cache"></param>
    /// <returns></returns>
    public Sprite LoadSprite(string path, bool cache = false)
    {
        if (spriteDic.TryGetValue(path, out var sprite)) return sprite;
        sprite = Resources.Load<Sprite>(path);
        if (cache)
        {
            spriteDic.Add(path, sprite);
        }

        return sprite;
    }
    
    /// <summary>
    /// 加载预设体
    /// </summary>
    /// <param name="path"></param>
    /// <param name="transform"></param>
    /// <param name="cache"></param>
    /// <returns></returns>
    public GameObject LoadPrefab(string path, Transform transform = null, bool cache = false)
    {
        if (!gameDic.TryGetValue(path, out var prefab))
        {
            prefab = Resources.Load<GameObject>(path);
            if (cache) { gameDic.Add(path, prefab); }
        }
        
        GameObject game = null;
        if (prefab) { game = transform != null ? Instantiate(prefab, transform) : Instantiate(prefab); }


        return game;
    }
    
    /// <summary>
    /// 加载音频资源文件
    /// </summary>
    /// <param name="path"></param>
    /// <param name="cache"></param>
    /// <returns></returns>
    public AudioClip LoadAudio(string path,  bool cache = false)
    {
        if (!audioDic.TryGetValue(path, out var audioClip))
        {
            audioClip = Resources.Load<AudioClip>(path);
            if (cache) { audioDic.Add(path, audioClip); }
        }
        return audioClip;
    }


    #region 英雄

    private void InitUnitConfig(string path)
    {
        TextAsset xml = Resources.Load<TextAsset>(path);
        if (!xml)
        {
            Debug.LogError("xml file:" + path + "not exist");  
        }
        else
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml.text);

            XmlNodeList nodeList = doc.SelectSingleNode("root")?.ChildNodes;
            for (var i = 0; i < nodeList?.Count; i++)
            {
                XmlElement element = nodeList[i] as XmlElement;
                if (element == null || element.GetAttributeNode("ID") == null) { continue; }

                var ID = Convert.ToInt32(element.GetAttributeNode("ID")?.InnerText);

                UnitConfig hero = new UnitConfig();
                
                foreach (XmlElement e in nodeList[i].ChildNodes)
                {
                    switch (e.Name)
                    {
                        case "unitId":
                            hero.unitId = int.Parse(e.InnerText);
                            break;
                        case "unitName":
                            hero.unitName = e.InnerText;
                            break;
                        case "resName":
                            hero.resName = e.InnerText;
                            break;
                        case "hitHeight":
                            hero.hitHeight = (PEInt) float.Parse(e.InnerText);
                            break;
                        case "hp":
                            hero.hp = int.Parse(e.InnerText);
                            break;
                        case "def":
                            hero.def = int.Parse(e.InnerText);
                            break;
                        case "moveSpeed":
                            hero.moveSpeed = int.Parse(e.InnerText);
                            break;
                        case "colliderConfig":
                        {
                            string[] value = e.InnerText.Split("#");

                            ColliderConfig colliderConfig = new ColliderConfig
                            {
                                mType = (ColliderType) Enum.Parse(typeof(ColliderType), value[0]),
                                mRadius = (PEInt) float.Parse(value[1])
                            };
                            hero.colliderConfig = colliderConfig;
                        }
                            break;
                        case "pasvBuff":
                        {
                            if (!e.InnerText.Equals("null"))
                            {
                                var value = e.InnerText.Split(",").Select(int.Parse).ToArray();
                                hero.pasvBuff = value.Length > 0 ? value : null;
                            }
                            else
                            {
                                hero.pasvBuff = null;
                            }
                            
                        }
                            break;
                        case "skillArr":
                        {
                            var value = e.InnerText.Split(",").Select(int.Parse).ToArray();
                            hero.skillArr = value.Length > 0 ? value : null;
                        }
                            break;
                    }
                }
                unitDataDic.Add(ID, hero);
            }
        }
    }

    public UnitConfig GetUnitConfigData(int id)
    {
        return unitDataDic.TryGetValue(id, out var data) ? data : null;
    }
    #endregion

    #region 地图

    private void InitMapConfig(string path)
    {
        TextAsset xml = Resources.Load<TextAsset>(path);
        if (!xml)
        {
            Debug.LogError("xml file:" + path + "not exist");  
        }
        else
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml.text);

            XmlNodeList nodeList = doc.SelectSingleNode("root")?.ChildNodes;
            for (var i = 0; i < nodeList?.Count; i++)
            {
                XmlElement element = nodeList[i] as XmlElement;
                if (element == null || element.GetAttributeNode("ID") == null) { continue; }

                var ID = Convert.ToInt32(element.GetAttributeNode("ID")?.InnerText);

                MapConfig map = new MapConfig();
                
                foreach (XmlElement e in nodeList[i].ChildNodes)
                {
                    switch (e.Name)
                    {
                        case "mapId":
                            map.mapId = int.Parse(e.InnerText);
                            break;
                        case "blueBorn":
                        {
                            string[] value = e.InnerText.Split(",");
                            map.blueBorn = new PEVector3(int.Parse(value[0]), int.Parse(value[1]), int.Parse(value[2]));
                            
                        }
                            break; 
                        case "redBorn":
                        {
                            string[] value = e.InnerText.Split(",");
                            map.redBorn = new PEVector3(int.Parse(value[0]), int.Parse(value[1]), int.Parse(value[2]));
                            
                        }  
                            break; 
                        case "towerIdArr":
                        {
                            var value = e.InnerText.Split(",").Select(int.Parse).ToArray();
                            map.towerIdArr = value;
                        }
                            break; 
                        case "towerPosArr":
                        {
                            var value = e.InnerText.Split("#");
                            var towerPosArr = new PEVector3[] { }; 
                            var tempList = new List<PEVector3>(towerPosArr);
                            for (var index = 0; index < value.Length; index++)
                            {
                                if (index == 0) { continue; }
                                var temp = value[index].Split(",");
                                tempList.Add(new PEVector3(
                                    temp[0].Contains("-") ? -(PEInt) Math.Abs(float.Parse(temp[0])) : (PEInt) float.Parse(temp[0]),
                                    int.Parse(temp[1]),
                                    temp[2].Contains("-") ? -(PEInt) Math.Abs(float.Parse(temp[2])) : (PEInt) float.Parse(temp[2]))
                                );
                            }
                            map.towerPosArr = tempList.ToArray();
                        }
                            break;
                        case "bornDelay":
                            map.bornDelay = int.Parse(e.InnerText);
                            break;
                        case "bornInterval":
                            map.bornInterval = int.Parse(e.InnerText);
                            break;
                        case "waveInterval":
                            map.waveInterval = int.Parse(e.InnerText);
                            break;
                        case "blueSoldierIdArr":
                        {
                            var value = e.InnerText.Split(",").Select(int.Parse).ToArray();
                            map.blueSoldierIdArr = value;
                        }
                            break; 
                        case "blueSoldierPosArr":
                        {
                            var value = e.InnerText.Split("#");
                            var blueSoldierPosArr = new PEVector3[] { }; 
                            var tempList = new List<PEVector3>(blueSoldierPosArr);
                            tempList.AddRange(value.Where((t, index) => index != 0)
                                .Select(t => t.Split(","))
                                .Select(temp => new PEVector3(int.Parse(temp[0]), int.Parse(temp[1]), temp[2].Contains("-") ? -(PEInt)Math.Abs(float.Parse(temp[2])) : (PEInt)float.Parse(temp[2]))));
                            map.blueSoldierPosArr = tempList.ToArray();
                            
                        }
                            break;
                        case "redSoldierIdArr":
                        {
                            var value = e.InnerText.Split(",").Select(int.Parse).ToArray();
                            map.redSoldierIdArr = value;
                            break; 
                        }
                        case "redSoldierPosArr":
                        {
                            var value = e.InnerText.Split("#");
                            var redSoldierPosArr = new PEVector3[] { }; 
                            var tempList = new List<PEVector3>(redSoldierPosArr);
                            tempList.AddRange(value.Where((t, index) => index != 0).
                                Select(t => t.Split(","))
                                .Select(temp => new PEVector3(int.Parse(temp[0]), int.Parse(temp[1]), temp[2].Contains("-") ? -(PEInt)Math.Abs(float.Parse(temp[2])) : (PEInt)float.Parse(temp[2]))));
                            map.redSoldierPosArr = tempList.ToArray();
                            
                        }
                            break;

                    }
                }
                mapDataDic.Add(ID, map);
            }
        }
    }

    public MapConfig GetMapConfigData(int id)
    {
        if (mapDataDic.TryGetValue(id, out var data))
        {
            return data;
        }

        return null;
    }
    #endregion
    
    public SkillConfig GetSkillConfigById(int skillId) {
        switch(skillId) {
            case 1010:
                return ResSkillConfig.sk_1010;
            case 1011:
                return ResSkillConfig.sk_1011;
            case 1012:
                return ResSkillConfig.sk_1012;
            case 1013:
                return ResSkillConfig.sk_1013;
            case 1014:
                return ResSkillConfig.sk_1014;
            case 1020:
                return ResSkillConfig.sk_1020;
            case 1021:
                return ResSkillConfig.sk_1021;
            case 1022:
                return ResSkillConfig.sk_1022;
            case 1023:
                return ResSkillConfig.sk_1023;
            case 1024:
                return ResSkillConfig.sk_1024;
            case 1025:
                return ResSkillConfig.sk_1025;
            case 1026:
                return ResSkillConfig.sk_1026;

            //防御塔与水晶的技能
            case 10010:
                return ResSkillConfig.sk_10010;
            case 10020:
                return ResSkillConfig.sk_10020;
            case 10030:
                return ResSkillConfig.sk_10030;
            case 10040:
                return ResSkillConfig.sk_10040;
            case 20010:
                return ResSkillConfig.sk_20010;
            case 20020:
                return ResSkillConfig.sk_20020;
            case 20030:
                return ResSkillConfig.sk_20030;
            case 20040:
                return ResSkillConfig.sk_20040;
            default:
                Debug.LogError($"Get Skill Config Failed,skillID:{skillId}");
                return null;
        }
    }
    
    public BuffCfg GetBuffConfigById(int buffID) {
        switch(buffID) {
            case 10100:
                return ResBuffConfig.buff_10100;
            //Arthur1技能
            case 10110://移速加速
                return ResBuffConfig.buff_10110;
            case 10111:
                return ResBuffConfig.buff_10111;
            case 10140:
                return ResBuffConfig.buff_10140;
            case 10141:
                return ResBuffConfig.buff_10141;
            case 10142:
                return ResBuffConfig.buff_10142;
            //Arthur2技能
            case 10120:
                return ResBuffConfig.buff_10120;
            //Arthur3技能
            case 10130:
                return ResBuffConfig.buff_10130;
            case 10131:
                return ResBuffConfig.buff_10131;
            case 10132:
                return ResBuffConfig.buff_10132;
            case 10133:
                return ResBuffConfig.buff_10133;
            //Houyi被动技能
            case 10200:
                return ResBuffConfig.buff_10200;
            case 10201:
                return ResBuffConfig.buff_10201;
            case 10250:
                return ResBuffConfig.buff_10250;
            //Houyi1技能
            case 10210://技能替换
                return ResBuffConfig.buff_10210;
            case 10240://scatter
                return ResBuffConfig.buff_10240;
            case 10260://mixed
                return ResBuffConfig.buff_10260;
            //Houyi2技能
            case 10220:
                return ResBuffConfig.buff_10220;
            case 10221:
                return ResBuffConfig.buff_10221;
            case 10222:
                return ResBuffConfig.buff_10222;
            case 10223:
                return ResBuffConfig.buff_10223;
            //Houyi3技能
            case 10230:
                return ResBuffConfig.buff_10230;
            case 10231:
                return ResBuffConfig.buff_10231;
            //通用
            case 90000:
                return ResBuffConfig.buff_90000;
            default:
                break;
        }
        Debug.LogError("Get Buff Config Failed,buffID:" + buffID);
        return null;
    }
    
    public Buff CreateBuff(MainLogicUnit source, MainLogicUnit owner, Skill skill, int buffID, object[] args) {
        var cfg = GetBuffConfigById(buffID);
        switch(cfg.buffType) {
            case BuffTypeEnum.MoveAttack:
                return new MoveAttackBuff(source, owner, skill, buffID, args);
            case BuffTypeEnum.MoveSpeed_Single:
                return new MoveSpeedBuff_Single(source, owner, skill, buffID, args);
            case BuffTypeEnum.MoveSpeed_DynamicGroup:
                return new MoveSpeedBuff_DynamicGroup(source, owner, skill, buffID, args);
            case BuffTypeEnum.ModifySkill:
                return new CommonModifySkillBuff(source, owner, skill, buffID, args);
            case BuffTypeEnum.Silense:
                return new SilenseBuff_Single(source, owner, skill, buffID, args);
            case BuffTypeEnum.ArthurMark:
                return new ArthurMarkBuff(source, owner, skill, buffID, args);
            case BuffTypeEnum.HPCure:
                return new HPCureBuff_Single(source, owner, skill, buffID, args);
            case BuffTypeEnum.Knockup_Group:
                return new KnockUpBuff_Group(source, owner, skill, buffID, args);

            case BuffTypeEnum.Damage_DynamicGroup:
                return new DamageBuff_DynamicGroup(source, owner, skill, buffID, args);
            case BuffTypeEnum.TargetFlashMove:
                return new TargetFlashMoveBuff(source, owner, skill, buffID, args);
            case BuffTypeEnum.ExecuteDamage:
                return new ExecuteDamageBuff(source, owner, skill, buffID, args);
            case BuffTypeEnum.Damage_StaticGroup:
                return new DamageBuff_StaticGroup(source, owner, skill, buffID, args);

            case BuffTypeEnum.HouyiPasvAttackSpeed:
                return new HouyiPasvAttackSpeedBuff(source, owner, skill, buffID, args);
            case BuffTypeEnum.HouyiPasvSkillModify:
                return new HouyiMultipleSkillModifyBuff(source, owner, skill, buffID, args);
            case BuffTypeEnum.HouyiPasvMultiArrow:
                return new HouyiMultipleArrowBuff(source, owner, skill, buffID, args);
            case BuffTypeEnum.HouyiActiveSkillModify:
                return new HouyiScatterSkillModifyBuff(source, owner, skill, buffID, args);
            case BuffTypeEnum.Scatter:
                return new HouyiScatterArrowBuff(source, owner, skill, buffID, args);
            case BuffTypeEnum.HouyiMixedMultiScatter:
                return new HouyiMixedMultiScatterBuff(source, owner, skill, buffID, args);
            case BuffTypeEnum.MoveSpeed_StaticGroup:
                return new MoveSpeedBuff_StaticGroup(source, owner, skill, buffID, args);

            case BuffTypeEnum.Stun_Single_DynamicTime:
                return new StunBuff_DynamicTime(source, owner, skill, buffID, args);
            //TOADD
            case BuffTypeEnum.None:
            default:
                Debug.LogError("Create Buff Failed,BuffID:" + buffID);
                return null;
        }
    }
    
    public Bullet CreateBullet(MainLogicUnit source, MainLogicUnit target, Skill skill) {
        switch(skill.config.bulletCfg.bulletType) {
            case BulletTypeEnum.SkillTarget:
                return new TargetBullet(source, target, skill);
            case BulletTypeEnum.UIDirection:
                return new DirectionBullet(source, skill);
            case BulletTypeEnum.UIPosition:
            case BulletTypeEnum.BuffSearch:
            default:
                Debug.LogError("Create Bullet Error.");
                return null;
        }
    }
}
